#!/usr/bin/perl

# ---------- Init variables -------
#my $version = "0.0001";
# ---------- external readable parameters -------
## Functions
##-------------------------------------------------------
#
# stict syntax checking.
require Exporter;
use strict;
use SIM_settings;
use SIM_base;
use CGI qw(param);

#my $httpUser = $ENV{'REMOTE_USER'} || die "Oops no env found for SREMOTE_USER.";
my $module = $ARGV[0];
my $tool = $ARGV[1];
my $action = $ARGV[2];
my $option1 = $ARGV[3];
my $option2 = $ARGV[4];
my $option3 = $ARGV[5];
my $option4 = $ARGV[6];

my @asaTestIndex;
my %asaTestValue = ();
my %asaTestType = ();
my @iosTestIndex;
my %iosTestValue = ();
my %iosTestType = ();
my @catTestIndex;
my %catTestValue = ();
my %catTestType = ();
my %healthData = ();
my %healthDescription = ();
my %healthType = ();
my %aliasList = ();


sub printHead {
  my $dispHead = "@_[0]";
  print("
        <TABLE WIDTH=100% BORDER=0 CELLSPACING=0><TR BGCOLOR=#EEEEEE><TD COLSPAN=3><CENTER>
        Options:
        <A HREF=$httpScriptName?$module+$tool+healthCheck+perl>Healthcheck</A> <FONT COLOR=#333333>|</FONT>
	</TD></TR>
	</TABLE>
	<CENTER>
        ");
}

sub readHealthcheckTables {
  my $configFile;
  if ( -f "$SIMparam{'SIMdataConfigs'}/healthcheck.txt" ) { 
    $configFile = "$SIMparam{'SIMdataConfigs'}/healthcheck.txt"; 
  } elsif ( -f "$SIMparam{'SIMmainConfigDir'}/healthcheck.txt" ) { 
    $configFile = "$SIMparam{'SIMmainConfigDir'}/healthcheck.txt"; 
  }
  if ( ! -r $configFile ) {
    print("Oops, no healthcheck config file to read. Add in Extra, Configs data the file healthcheck.txt.");
  } else {
    open ( CONF, $configFile );
    # temporary config file with new syntax
    open ( NEWCONF, ">$configFile.new");
    my @healthcheckInfo = <CONF>;
    close CONF;
    my $num = 0;
    my $lineNum = 0;
    foreach my $line (@healthcheckInfo) {
      chomp $line;
      my ( $devType, $name, $info ) = split(' ', $line, 3);
      $lineNum++;
      my $nameNum = sprintf("%08d", $lineNum);
      # need to look into the numbering of the checks.
      #$name = "$nameNum-$name";
      # section name is numeric (no longer needed).
      $name = "$nameNum";
      if (( "$devType" eq "ios" ) or ( "$devType" eq "asa" ) or ( "$devType" eq "cat" )) {
#       print("Line: devType=$devType, name=$name, info=$info<BR>");
        my ( $testDescription, $testData ) = split('-DATA-', $info);
	$healthType{$name} = $devType;
	$healthDescription{$name} = $testDescription;
        print NEWCONF "$devType\n  section: default\n  prefix:\n  descr: $testDescription\n  comment:\n";
	$healthData{$name} = $testData;
        my @testEntries = split('-OR-', $testData);
        foreach my $entry (@testEntries) {
	  my $testName = testNameStrict( $entry, "email" );
          $num++;
	  my ( $checkType, $checkData ) = split(' ', $entry, 2);
          if (( "$checkType" eq "ifMatch" ) or ( "$checkType" eq "ifBegin" ) or ( "$checkType" eq "hasNot" ) or ( "$checkType" eq "onError" )) {
            print NEWCONF "  test: $checkType $checkData\n";
            if ( "$devType" eq "ios" ) {
              push( @iosTestIndex, $testName );
	      $iosTestType{$testName} = $checkType;
	      $iosTestValue{$testName} = $checkData;
#	      print("testName=$testName, checkType=$checkType<BR>");
	    } elsif ( "$devType" eq "asa" ) {
              push( @asaTestIndex, $testName );
	      $asaTestType{$testName} = $checkType;
	      $asaTestValue{$testName} = $checkData;
	    } elsif ( "$devType" eq "cat" ) {
              push( @catTestIndex, $testName );
	      $catTestType{$testName} = $checkType;
	      $catTestValue{$testName} = $checkData;
	    }
	  }
	}
        print NEWCONF "!\n";
      }
    }
    close( NEWCONF );
  }
# while ( my ($key, $value) = each(%iosTestValue) ) { print "ios: $key => $value<BR>"; }
# while ( my ($key, $value) = each(%asaTestValue) ) { print "asa: $key => $value<BR>"; }
# print("<BR>Aliaslist: $SIMparam{'SIMhealthcheckAliases'}");
  if ( -f $SIMparam{'SIMhealthcheckAliases'} ) {
    if ( -r $SIMparam{'SIMhealthcheckAliases'} ) {
      open ( CONF, $SIMparam{'SIMhealthcheckAliases'} );
      my @info = <CONF>;
      close CONF;
      foreach my $line (@info) {
        my ( $type, $alias, $host ) = split(' ', $line);
	if ( "$type" eq "alias" ) {
#	  print("<BR>$alias $host");
	  $aliasList{$alias} = $host;
	}
      }
    }
  }
}

sub displayLogging {
  my $ipAddr = "@_[0]";
  my %testEntry = ();
  my $ipDir = getIpDir( $ipAddr );
  my $firstMac = catFileLine("$ipDir/firstmac.txt");
  my @ipEntries = <$SIMparam{'SIMmacDatab'}/$firstMac/ipint-*.txt>;
  foreach my $entry (@ipEntries) {
    my $info = catFileLine( $entry );
    my ( $ipAddr, $rest ) = split(' ', $info);
    print("<!-- getDnsPtr: $ipAddr. ");
    my $deviceName = getDnsPtr( $ipAddr );
    print("-->");
    if ( "$deviceName" ne "" ) {
      $testEntry{$deviceName} = 1;
    }
    $testEntry{$ipAddr} = 1;
  }
  if ( -d $SIMparam{'SIMsyslogDir'} ) {
    chdir $SIMparam{'SIMsyslogDir'};
    my @syslogDir = <*>;
    my $info;
    my $reportLog;
    # show the newest date first
    my @revSyslogDir = reverse(@syslogDir);
    foreach my $entry (@revSyslogDir) {
      foreach my $testItem (keys %testEntry) {
#       print("<TR><TD COLSPAN=9>Testing $entry/$testItem/all-messages</TD></TR>");
        if ( -f "$SIMparam{'SIMsyslogDir'}/$entry/$testItem/all-messages" ) {
          $info = ` tail -n 5 $SIMparam{'SIMsyslogDir'}/$entry/$testItem/all-messages `;
	  $info =~ s/\n/<BR>/g;
          last;
        }
      }
      if ( "$info" ne "" ) {
        $reportLog = $entry;
        last;
      }
    }
    if ( "$info" ne "" ) {
      print("<TR><TD></TD><TD COLSPAN=9 BGCOLOR=#DDDDDD>Syslog info: $reportLog</TD></TR>
             <TR><TD></TD><TD COLSPAN=9>$info</TD></TR>");
    } else {
      print("<TR><TD></TD><TD COLSPAN=4>Syslog info:</TD><TD BGCOLOR=#FF6600 COLSPAN=5>No syslog info found.</TD></TR>");
    }
  }
}

sub healthCheck {
  print("<H2>Compliancy tester</H2>");
  my $healthCheckDevices = $SIMparam{'SIMhealthCheckDevices'};
  my @healthCheckTypes = split(' ', $healthCheckDevices);
  my $seedList = param("seedList");
  my $devType = param("devType");
  if (( "$seedList" eq "" ) and ( "$devType" eq "" )) {
    print("Specify the hostnames you want to check.
      <FORM method=post Action=$httpScriptName?$module+$tool+healthCheck>
      <TEXTAREA NAME=\"seedList\" ROWS=20 COLS=100></TEXTAREA><BR>
      <B><FONT SIZE=+0>Or specify the devicetype you want to check</FONT></B>
      <SELECT NAME=devType SIZE=1>
        <OPTION VALUE=>Select device type</OPTION>");
    foreach my $devType (@healthCheckTypes) {
      print("<OPTION VALUE=$devType>$devType</OPTION>");
    }
    print("</SELECT>	
      <INPUT TYPE=submit Value=\"Process\">
      </FORM>
          ");
  } else {
    my @entries = ();
    if (( "$devType" ne "" ) and ( -d "$SIMparam{'SIMdeviceDir'}/$devType")) {
      chdir "$SIMparam{'SIMdeviceDir'}/$devType";
      @entries = <*>;
    } else {
      @entries = split(' ', $seedList);
#     my $tmpList = join(';', @entries);
#     printDebug( 0, "entries=$tmpList");
    }
    my %testedHosts = ();
    if ( "$healthCheckDevices" eq "" ) {
      print("<H3>No device type found to check, specify SIMhealthCheckDevices in the settings2.conf</H3>");
    } else {
      readHealthcheckTables;
      print("<TABLE>");
      foreach my $entry (@entries) {
        $entry = lc($entry);
	if ( "$aliasList{$entry}" eq "" ) {
          print("<TR BGCOLOR=#FFFF00><TD BGCOLOR=#FFFF00>$entry</TD><TD COLSPAN=9></TD></TR>");
	} else {
          print("<TR BGCOLOR=#FFFF00><TD BGCOLOR=#FFFF00>$entry</TD><TD COLSPAN=9>alias: $aliasList{$entry}</TD></TR>");
	  $entry = $aliasList{$entry};
	}
	my $foundDev = "no";
        foreach my $devType (@healthCheckTypes) {
	  chdir "$SIMparam{'SIMdeviceDir'}/$devType";
          my @devNames = <$entry*>;
          foreach my $deviceName (@devNames) {
	    $testedHosts{$deviceName} = "$entry";
	    $foundDev = "yes";
	    my $ipAddr = catFileLine("$SIMparam{'SIMdeviceDir'}/$devType/$deviceName/ipaddr");
	    print("<TR><TD></TD><TD COLSPAN=9 BGCOLOR=#FFFF88>
	      <A HREF=$httpScriptName?mon+nodestatus+$ipAddr>$deviceName</A> ($devType)</TD></TR>");
	    my $statusColor;
	    my $ipDir = getIpDir( $ipAddr );
	    my $recType = catFileLine("$ipDir/sipmanrectype.txt");
	    if ( "$recType" eq "ext" ) {
	      print("<TR><TD></TD><TD COLSPAN=9>Device externaly managed</TD></TR>");
	    } elsif ( "$recType" eq "standby" ) {
	      print("<TR><TD></TD><TD COLSPAN=9>Standby device, has only a copy config.</TD></TR>");
	    } elsif ( -f "$SIMparam{'SIMdevConfigCurrent'}/$deviceName" ) {
              # display the heathcheck info defined for the node
              my $devDir = getDevDir($ipAddr);
              my $healthCheckInfo = catFileLine("$devDir/healthcheckInfo");
              if ( $healthCheckInfo ne "" ) {
                 print("<TR><TD></TD><TD COLSPAN=2>Healthcheck info</TD><TD COLSPAN=7>$healthCheckInfo</TD></TR>");
              }
              # display the date the config was last updated.
	      my $lastTested = catFileLine("$SIMparam{'SIMdevConfigInfo'}/tested-$deviceName","never tested");
	      if ( "$lastTested" eq "never tested" ) {
	        $statusColor = "orange";
	      } else {
	        $statusColor = "white";
	      }
	      print("<TR><TD></TD><TD COLSPAN=2>Config file last uploaded / checked</TD><TD COLSPAN=7 BGCOLOR=$statusColor>$lastTested</TD></TR>");
	      my $logFacility = testDeviceConfig( "$SIMparam{'SIMdevConfigCurrent'}/$deviceName", $deviceName, $entry);
	    } else {
	      print("<TR><TD></TD><TD COLSPAN=2>Config file last checked</TD><TD COLSPAN=7 BGCOLOR=#FF6600>missing</TD></TR>");
	    }
	    if ( "$recType" ne "ext" ) {
              displayLogging( $ipAddr );
	    }
          }
        }
	if ( "$foundDev" eq "no" ) {
	  print("<TR><TD></TD><TD COLSPAN=9 BGCOLOR=#FF6600>No device info found for $entry.</TD></TR>");
	}
      }
      foreach my $devType (@healthCheckTypes) {
        chdir "$SIMparam{'SIMdeviceDir'}/$devType";
	my @hostList = <*>;
	foreach my $entry (@hostList) {
	  if ( "$testedHosts{$entry}" eq "" ) {
	    my $ipAddr = catFileLine("$SIMparam{'SIMdeviceDir'}/$devType/$entry/ipaddr");
	    my $ipDir = getIpDir($ipAddr);
	    my $recType = catFileLine("$ipDir/sipmanrectype.txt");
	    if ( "$recType" ne "ext" ) {
	      print("<TR BGCOLOR=#FF6600><TD></TD><TD COLSPAN=9>Device $entry not in the seedList.</TD></TR>");
	    }
	  }
	}
      }
      print("</TABLE>");
    }
  }
}

sub testDeviceConfig {
  my $configName = "@_[0]";
  my $deviceName = "@_[1]";
  my $testName = "@_[2]";
  open( CONF, $configName );
  my @info = <CONF>;
  close CONF;
  my $type;
  my %testType = ();
  my %testValue = ();
  my %testResult = ();
  my $logFacility;
# print("<TR><TD></TD><TD COLSPAN=9><B>Config file checks</B></TD></TR>");
  my @testIndex;
  foreach my $line (@info) {
#   print "<TR><TD></TD><TD COLSPAN=9>size of hash:  " . keys( %testValue ) . ".</TD></TR>";
    chomp $line;
    my @entry = split(' ', $line);
    if ( "$type" eq "" ) {
      if (( "$entry[0] $entry[1]" eq "PIX Version" ) or ( "$entry[0] $entry[1]" eq "ASA Version" )
           or ( "$entry[0] $entry[1]" eq "FWSM Version" )) {
        $type = "asa";
        print("<TR><TD></TD><TD COLSPAN=9><B>Config file checks, type is $type</B></TD></TR>");
        @testIndex = @asaTestIndex;
        %testType = %asaTestType;
	%testValue = %asaTestValue;
#	print("<TR><TD></TD><TD COLSPAN=9>"); while ( my ($key, $value) = each(%testValue) ) { print "asa: $key => $value<BR>"; } print("</TD></TR>");
      } elsif ( "$entry[0]" eq "version" ) {
        $type = "ios";
        print("<TR><TD></TD><TD COLSPAN=9><B>Config file checks, type is $type</B></TD></TR>");
        @testIndex = @iosTestIndex;
        %testType = %iosTestType;
	%testValue = %iosTestValue;
#	print("<TR><TD></TD><TD COLSPAN=9>"); while ( my ($key, $value) = each(%testValue) ) { print "ios: $key => $value<BR>"; } print("</TD></TR>");
      } elsif ( "$entry[0]" eq "#version" ) {
        $type = "cat";
	print("<TR><TD></TD><TD COLSPAN=9><B>Config file checks, type is $type</B></TD></TR>");
	%testType = %catTestType;
	%testValue = %catTestValue;
      }
#     if ( "$type" ne "" ) { my $test = join(' ', @testIndex); print("<TR><TD COLSPAN=9>testIndex=$test</TD></TR>"); }
    } elsif ( "$entry[0] $entry[1]" eq "logging facility" ) {
      $logFacility = $entry[2];
    } elsif ( "$entry[0] $entry[1] $entry[2] $entry[3]" eq "set logging server facility" ) {
      $logFacility = $entry[4];
    } else {
#     while ( my ($key, $value) = each(%testValue) ) {
#     print("<TR><TD></TD><TD COLSPAN=9>Reading: $line</TD></TR>");
      foreach my $key (@testIndex) {
        my $value = $testValue{$key};
#       print("<BR>key=$key, value=$value line=$line: ");
        my @testWords = split(' ', $value);
	my $num = 0;
        #tmpLine used to hide password entries...
        my $tmpLine = "";
	foreach my $word (@testWords) {
#         print("<TR><TD></TD><TD COLSPAN=9>word:$word, num=$num, entry:$entry[$num].</TD></TR>");
          if (  "$word" eq "-password-" ) {
            $line = "$tmpLine ........";
          } elsif (  "$word" eq "-ipaddr-" ) {
            my $testIfAddr =  testIfIp($entry[$num]);
#           print("<TR><TD></TD><TD COLSPAN=9>word:$word, entry:$entry[$num], testIfAddr:$testIfAddr.</TD></TR>");
            if ( $testIfAddr eq "oke" ) {
              # entry is an ipaddr, continue
              $num++;
            } else {
              $num = "x";
              last;
            }
	  } elsif (( "$word" ne "$entry[$num]" ) and ( "$word" ne "-dummy-" )) {
            # if entries don't match, skip
	    $num = "x";
	    last;
	  } else {
	    $num++;
	  }
          $tmpLine = "$tmpLine $word";
	}
	if ( "$num" ne "x" ) {
#	  print("<TR><TD COLSPAN=9>found $key:$value:$line.</TD></TR>\n");
	  $testResult{$key} = "$testResult{$key}$line<BR>";
	  last;
	}
      }
    }
  }
# while ( my ($key, $value) = each(%healthData) ) {
  foreach my $key (sort keys %healthData) {
#   print("<TR><TD COLSPAN=9>key=$key.</TD></TR>\n");
    if ( "$healthType{$key}" eq "$type" ) {
#   my @testEntries = split('-OR-', $value);
    my @testEntries = split('-OR-', $healthData{$key});
    my $lineColor;
    my $lineResult;
    foreach my $entry (@testEntries) {
      my $testName = testNameStrict( $entry, "email" );
      my ( $checkType, $checkData ) = split(' ', $entry, 2);
      if (( "$checkType" eq "ifMatch" ) or ( "$checkType" eq "ifBegin" )) {
        if ( "$testResult{$testName}" ne "" ) {
	  $lineColor = "white";
	  $lineResult = $testResult{$testName};
#     print("<TR><TD COLSPAN=9>A entry=$entry, testName=$testName, checkType=$checkType, checkData=$checkData, lineResult=$testResult{$testName}</TD></TR>");
	  last;
	} else {
#         print("<TR><TD COLSPAN=9>B entry=$entry, testName=$testName, checkType=$checkType, checkData=$checkData, lineResult=$testResult{$testName}</TD></TR>");
	  $lineColor = "#FF6600";
	}
      } elsif ( "$checkType" eq "hasNot" ) {
        if ( "$testResult{$testName}" eq "" ) {
	  $lineColor = "white";
#     print("<TR><TD COLSPAN=9>entry=$entry, testName=$testName, checkType=$checkType, checkData=$checkData, lineResult=$testResult{$testName}</TD></TR>");
	  last;
	} else {
	  $lineResult = $testResult{$testName};
	  $lineColor = "#FF6600";
	}
      } elsif ( "$checkType" eq "onError" ) {
        if (( "$testResult{$testName}" ne "" ) and ( "$lineResult" eq "" )) {
	  $lineResult = $testResult{$testName};
	}
      }
#     print("<TR><TD COLSPAN=9>C entry=$entry, testName=$testName, checkType=$checkType, checkData=$checkData, lineResult=$testResult{$testName}</TD></TR>");
    }
    if ( "$lineResult" eq "" ) {
      $lineResult  = "not configured"
    }
    print("<TR><TD></TD><TD COLSPAN=4 VALIGN=top>$healthDescription{$key}</TD><TD COLSPAN=5 BGCOLOR=$lineColor VALIGN=top>$lineResult</TD></TR>");
    }
  }
  return $logFacility;
}

#--------------------------- Main ---------------------------
printHead;


if ( "$action" eq "none" ) {
  $action = "healthCheck";
}
if ( "$action" eq "healthCheck" ) {
  healthCheck($option1);
} elsif ( "$action" eq "testEnv" ) {
  testEnv($option1);
} elsif ( "$action" eq "grep" ) {
  grepMain($option1);
} else {
  print("Oops, action $action not found.");
}
